#include <unistd.h>
#include <stdint.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

#include "typedefs.h"
#include "chip.h"
#include "hbi.h"
#include "app_util.h"
#include "fwr_image_headers.h"
/********************************************/
/*!
* \defgroup hbi_load_firmware hbi_load_firmware
*
* This sample app load firmware and configuration record  to Microsemi Vproc
* device.
*
* It support both Dynamic and Static image loading.
*
* Firmware and Configuration Record Image can be compiled as static C-based 
* array along with test app by OR can be loaded dynamically at run time.
*
* 
* For static compilation, user need to define following two macros at compile
* time along with TEST_FWR_LOAD
*  
* LOAD_FWR_STATIC -             Defined at Makefile. if defined, expects user to 
*                               provide a C header file containing firmware 
*                               boot image for static compilation
*
*
* LOAD_CFGREC_STATIC -          Defined at Makefile.if defined, expects user to
*                               provide C files containing configuration record
*
*
*
* if images are compiled in statically, run
*
* ./hbi_load_firmware -d <device ID> 
*
* For dynamic bootimage loading to device (undef LOAD_FWR_STATIC), run
*
* ./hbi_load_firmware -d <device ID> -i <filename> -c <cfgrec filename> 
*
* where firmware filename = binary firmware image with .bin extension. 
*
* configuration record filename = configuration record file with .cr2 extension
*
* For loading and saving to flash, use -s option
*
* ./hbi_load_firmware -d <device ID> -i <filename> -c <cfgrec filename> -s , or 
*
* ./hbi_load_firmware -d <device ID> -s
*
* \b NOTE - firmware binary image or c-output is generated by running Microsemi Provided
*        Image convertor tool. 
********************************************************************************/



/*! \ingroup test_load_firmware
 * \{
 *
*/
/*Initialized instance for each of the ZL device to support
 * Example definition for two devices and bus 0 and address 0-1
 *
 * Example for device 0 demonstrates compiling a static firmware and config 
 */

#if defined(HBI_BOOTLOAD_FWR_STATIC) || defined(HBI_BOOTLOAD_CFGREC_STATIC)
static hbi_dev_info_t hbi_devices_images[] = 
{
    {
        .pFirmware = (uint8_t *)zls38067_0_firmware, /*a pointer to the firmware data array  from *.h if in c code format*/
        .pConfig = (uint8_t *)zls38067_0_config,     /*a pointer to the config data array  from *.h if in c code format*/
    }, 
    {
        .pFirmware = NULL,
        .pConfig = NULL,
    }               
};
#endif

static hbi_handle_t handle;
void usage(void)
{
   printf("-i: firmware input filename\n");
   printf("-c: configuration record filename\n");
   printf("-s : save to flash after load\n");
   printf("Example\nTo load firmware and connfiguration record dynamically, run\n");
   printf("./hbi_load_firmware -d <device ID> -i <fwr filename.bin> -c <cfgrec filename.bin> \n");
   return;
}
void main (int argc, char** argv)
{
   hbi_dev_cfg_t devcfg;
   hbi_status_t  status;
   char *cfgrec=NULL;
   char *fwr=NULL;
   int  bSaveToFlash=0;
   int c;
   int fwrLoaded=0,cfgrecLoaded=0;
   user_buffer_t tmp[2];
   int imageNum;
   hbi_device_id_t deviceId = -1;
   
   while((c = getopt(argc,argv,"sc:i:d:h")) != -1)
   {
      switch(c)
      {
         case 'd':
            deviceId= strtol(optarg,NULL,16);
         break;
         case 's':
            bSaveToFlash=1;
         break;
         case 'c':
            cfgrec=optarg;
         break;
         case 'i':
            fwr = optarg;
            printf("inpath %s\n",fwr);
         break;
         case 'h':
         usage();
         return;
         default:
         break;
      }
   }
   
   printf("argc = %d \n", argc);
   printf("argv[argc -1] = %s \n", argv[argc-1]);
   
   if ((deviceId < 0) || (deviceId >=VPROC_MAX_NUM_DEVS))
   {
       printf("Incorrect deviceId - deviceID must be within 0 to %d \n", VPROC_MAX_NUM_DEVS-1);
       return;
   }
   
   devcfg.deviceId = deviceId;
   devcfg.pDevName = NULL;
   
   status = HBI_open(&handle,&devcfg);
   if(status != HBI_STATUS_SUCCESS)
   {
       printf("dev open error\n");
       return;
   }
#ifdef HBI_BOOTLOAD_FWR_STATIC
   if (hbi_devices_images[deviceId].pFirmware == NULL)
   {
       printf("Invalid argument pFirmware can not be pointed to NULL in static compilation mode...\n");
       HBI_close(handle);
       return; 
   }
   printf("Loading firmware static...\n");
  
   status=vproc_load_image(handle, hbi_devices_images[deviceId].pFirmware);
   printf("Loading firmware ...status = %d\n", status);
   if(status == HBI_STATUS_SUCCESS)
      fwrLoaded=1;
#else
   if(fwr != NULL)
   {
      status=vproc_load_image(handle,fwr);
      if(status == HBI_STATUS_SUCCESS)
         fwrLoaded=1;
   }
   else
   {
      /* if host is not loading boot image, there's no meaning of 
         save to flash as standalone config record save to flash is not 
         supported*/
        // bSaveToFlash=0;
   }
#endif

   if(status!=HBI_STATUS_SUCCESS)
   {
       printf("Error loading firmware\n");
       HBI_close(handle);
       return;
   }


#ifdef HBI_BOOTLOAD_CFGREC_STATIC
   if (hbi_devices_images[deviceId].pConfig == NULL)
   {
       printf("Invalid argument pConfig can not be pointed to NULL in static compilation mode...\n");
       HBI_close(handle);
       return; 
   }

   printf("Loading Configuration Record static...\n");
    
   status=vproc_load_image(handle,hbi_devices_images[deviceId].pConfig);
   if(status == HBI_STATUS_SUCCESS)
   {
       printf("Config Loading Done.\n");
       cfgrecLoaded=1;
   }
   else 
   {
      printf("Error loading config record\n");
   }
#else
   if(cfgrec != NULL)
   {

      printf("Loading Configuration Record...\n");

      status=vproc_load_image(handle,cfgrec);
      if(status == HBI_STATUS_SUCCESS)
      {
          printf("Config Loading Done.\n");
          cfgrecLoaded=1;
      }
      else 
      {
         printf("Error loading config record\n");
      }
   }
#endif

   if(fwrLoaded)
   {
      if(bSaveToFlash)
      {
         printf("\nSaving Firmware and Configuration Record to flash\n");
      
         status = HBI_set_command(handle, HBI_CMD_SAVE_FWRCFG_TO_FLASH, &imageNum);
         if (status != HBI_STATUS_SUCCESS) {
             printf("Error %d:HBI_set_command(HBI_CMD_SAVE_FWRCFG_TO_FLASH)\n", status);
         } else 
             printf("Image %d saved to flash \n", imageNum);
      }
      printf("\nStart Firmware\n");

      status = HBI_set_command(handle, HBI_CMD_START_FWR, NULL);
      if (status != HBI_STATUS_SUCCESS) 
      {
          printf("Error %d:HBI_set_command(HBI_CMD_START_FWR)\n", status);
      }
      
   }
   /* Apply a soft reset. */
   else 
   {

      if(cfgrecLoaded)
      {                      
         if(bSaveToFlash && (fwrLoaded==0))  
         {
             
            if ((argv[argc-1] == "-s")) {
                printf("Image number on flash for which to save Config is required after -s \n"); 
                status = HBI_close(handle);
                status = HBI_term();
                return;
            } else {
                imageNum = (uint8_t)strtol(argv[argc-1],NULL,16);
                printf("Saving Config %d to flash \n", imageNum);
                status = HBI_set_command(handle, HBI_CMD_SAVE_CFG_TO_FLASH, &imageNum);
                if (status != HBI_STATUS_SUCCESS) {
                    printf("Error %d:HBI_set_command(HBI_CMD_SAVE_FWRCFG_TO_FLASH, imagenum %d)\n", status, imageNum);
                } else
                    printf("Config %d saved to flash \n", imageNum);
            }
         } 
                                
         printf("SW reset after config record loading\n");
         tmp[0]=(ZL380xx_HOST_SW_FLAGS_APP_REBOOT>>8) & 0xFF;
         tmp[1]=ZL380xx_HOST_SW_FLAGS_APP_REBOOT & 0xFF;
        
         status = HBI_write(handle, ZL380xx_HOST_SW_FLAGS_REG, tmp, 2);
         if(status != HBI_STATUS_SUCCESS)
         {
             printf("SW reset failed after config record loading\n");
         }
      }
   }
   fwrLoaded=0;
   cfgrecLoaded=0;
   printf("Closing device file....\n");
   status = HBI_close(handle);
   if(status != HBI_STATUS_SUCCESS)
   {
       printf("dev close error\n");
   }

   return;
}


/** \} */

